﻿using System;
using System.Diagnostics;
using System.Linq;

namespace Creventive.Wpf.ShellFactory.Logging
{
    /// <summary>
    ///   A simple logger which does nothing but direct the log output to the trace window.
    /// </summary>
    public class TraceLogger : ILoggerService
    {
        #region Static Fields/Constants

        private static readonly TraceLogger defaultInstance = new TraceLogger();

        #endregion

        /// <summary>
        ///   Gets the default PassthroughLogger instance.
        /// </summary>
        /// <value>The default.</value>
        public static TraceLogger Default
        {
            get { return defaultInstance; }
        }

        /// <summary>
        ///   Writes the given data, tagging it with the specified type.
        /// </summary>
        /// <param name = "type">The type.</param>
        /// <param name = "data">The data.</param>
        protected virtual void Write(string type, object data)
        {
            Trace.WriteLine(SafeString(data), type);
        }

        private void WriteFormat(string type, string format, params object[] formatArguments)
        {
            if (formatArguments == null || formatArguments.Length == 0)
                this.Write(type, format);
            else
                this.Write(type, string.Format(SafeString(format), formatArguments.Select(SafeString).ToArray()));
        }

        private static string SafeString(object input)
        {
            if (input == null)
                return "(null)";
            else
                return input.ToString();
        }

        /// <summary>
        ///   Sends the provided information to the logger.
        /// </summary>
        /// <param name = "format">The format.</param>
        /// <param name = "formatArguments">The format arguments.</param>
        public void Info(string format, params object[] formatArguments)
        {
            this.WriteFormat("Info", format, formatArguments);
        }

        /// <summary>
        ///   Sends the provided information to the logger.
        /// </summary>
        /// <param name = "data">The data.</param>
        public void Info(object data)
        {
            this.Write("Info", data);
        }

        /// <summary>
        ///   Sends the provided warning to the logger.
        /// </summary>
        /// <param name = "format">The format.</param>
        /// <param name = "formatArguments">The format arguments.</param>
        public void Warning(string format, params object[] formatArguments)
        {
            this.WriteFormat("Warning", format, formatArguments);
        }

        /// <summary>
        ///   Sends the provided warning to the logger.
        /// </summary>
        /// <param name = "data">The data.</param>
        public void Warning(object data)
        {
            this.Write("Warning", data);
        }

        /// <summary>
        ///   Sends the provided error to the logger.
        /// </summary>
        /// <param name = "format">The format.</param>
        /// <param name = "formatArguments">The format arguments.</param>
        public void Error(string format, params object[] formatArguments)
        {
            this.WriteFormat("Error", format, formatArguments);
        }

        /// <summary>
        ///   Sends the provided error to the logger.
        /// </summary>
        /// <param name = "data">The data.</param>
        public void Error(object data)
        {
            this.Write("Error", data);
        }

        /// <summary>
        ///   Sends the provided error to the logger.
        /// </summary>
        /// <param name = "exception">The exception.</param>
        public void Error(Exception exception)
        {
            this.Write("Error", exception);
        }

        /// <summary>
        ///   Sends the provided error to the logger.
        /// </summary>
        /// <param name = "exception">The exception.</param>
        /// <param name = "format">The format.</param>
        /// <param name = "formatArguments">The format arguments.</param>
        public void Error(Exception exception, string format, params object[] formatArguments)
        {
            string header;
            if (formatArguments == null || formatArguments.Length == 0)
                header = SafeString(format);
            else
                header = string.Format(SafeString(format), formatArguments.Select(SafeString).ToArray());
            this.Write("Error", header + Environment.NewLine + SafeString(exception));
        }

        /// <summary>
        ///   Sends the provided error to the logger.
        /// </summary>
        /// <param name = "exception">The exception.</param>
        /// <param name = "data">The data.</param>
        public void Error(Exception exception, object data)
        {
            this.Write("Error", SafeString(data) + Environment.NewLine + SafeString(exception));
        }
    }
}